package com.vn.ld.btc.dao.common;

import org.springframework.beans.factory.annotation.Autowired;

import com.vn.ld.btc.dao.IIdCounterDao;
import com.vn.ld.btc.dao.entity.IdCounter;
import com.vn.ld.common.Constants;
import com.vn.ld.common.util.DateUtils;

public class IdGenerator {
	@Autowired
	private IIdCounterDao<IdCounter> idCounterDao;
	
	private IdCounter orderCounter;
	private Integer orderLocalCount = 0;
	private Integer orderCounterStep = Constants.ID_COUNTER_STEP_DEFAULT;
	
	private IdCounter transactionCounter;
	private Integer transactionLocalCount = 0;
	private Integer transactionCounterStep = Constants.ID_COUNTER_STEP_DEFAULT;
	
	private IdCounter depositCounter;
	private Integer depositLocalCount = 0;
	private Integer depositCounterStep = Constants.ID_COUNTER_STEP_DEFAULT;
	
	private IdCounter withdrawalCounter;
	private Integer withdrawalLocalCount = 0;
	private Integer withdrawalCounterStep = Constants.ID_COUNTER_STEP_DEFAULT;
	
	private static IdGenerator idGenerator;
	public static IdGenerator getInstance() {
		if (idGenerator == null) {
			idGenerator = new IdGenerator();
		}
		return idGenerator;
	}
	
	/**
	 * Generate unique order id.
	 *
	 * @return the string
	 */
	public synchronized String generateUniqueOrderId() {
		StringBuffer orderId = new StringBuffer();
		if (this.orderCounter == null || this.orderLocalCount >= this.orderCounterStep) {
			Integer currentCounter = 0;
			if (this.orderCounter != null) {
				currentCounter = this.orderCounter.getCurrentCounter();
			}
			
			this.orderCounter = this.idCounterDao.getByCounterKey(Constants.IdCounterKey.ORDER_ID_COUNTER_KEY);

			if (this.orderCounter != null && !this.orderCounterStep.equals(this.orderCounter.getCounterStep())) {
				this.orderCounterStep = this.orderCounter.getCounterStep();
			}
			
			if (this.orderLocalCount >= this.orderCounterStep) {
				this.orderCounter.setCurrentCounter(currentCounter + this.orderCounterStep);
				this.idCounterDao.save(this.orderCounter);
				this.orderLocalCount = 0;
			}
			
		}
		
		if (this.orderCounter != null) {
			String counterDate = DateUtils.dateToString(this.orderCounter.getCounterDate(), Constants.DATE_FORMAT_SECOND_TRUNCATE);
			orderId.append(counterDate);
			orderId.append(this.orderCounter.getCounterKey());
			orderId.append(this.orderCounter.getCurrentCounter());
			
			this.orderLocalCount++;
		}
		
		return orderId.toString();
	}
	
	/**
	 * Generate unique transaction id.
	 *
	 * @return the string
	 */
	public synchronized String generateUniqueTransactionId() {
		StringBuffer transactionId = new StringBuffer();
		if (this.transactionCounter == null || this.transactionLocalCount >= this.transactionCounterStep) {
			Integer currentCounter = 0;
			if (this.transactionCounter != null) {
				currentCounter = this.transactionCounter.getCurrentCounter();
			}
			
			this.transactionCounter = this.idCounterDao.getByCounterKey(Constants.IdCounterKey.TRANSACTION_ID_COUNTER_KEY);

			if (this.transactionCounter != null && !this.transactionCounterStep.equals(this.transactionCounter.getCounterStep())) {
				this.transactionCounterStep = this.transactionCounter.getCounterStep();
			}
			
			if (this.transactionLocalCount >= this.transactionCounterStep) {
				this.transactionCounter.setCurrentCounter(currentCounter + this.transactionCounterStep);
				this.idCounterDao.save(this.transactionCounter);
				this.transactionLocalCount = 0;
			}
		}
		
		if (this.transactionCounter != null) {
			String counterDate = DateUtils.dateToString(this.transactionCounter.getCounterDate(), Constants.DATE_FORMAT_SECOND_TRUNCATE);
			transactionId.append(counterDate);
			transactionId.append(this.transactionCounter.getCounterKey());
			transactionId.append(this.transactionCounter.getCurrentCounter());
			
			this.transactionLocalCount++;
		}
		
		return transactionId.toString();
	}
	
	/**
	 * Generate unique deposit id.
	 *
	 * @return the string
	 */
	public synchronized String generateUniqueDepositId() {
		StringBuffer depositId = new StringBuffer();
		if (this.depositCounter == null || this.depositLocalCount >= this.depositCounterStep) {
			Integer currentCounter = 0;
			if (this.depositCounter != null) {
				currentCounter = this.depositCounter.getCurrentCounter();
			}
			
			this.depositCounter = this.idCounterDao.getByCounterKey(Constants.IdCounterKey.TRANSACTION_ID_COUNTER_KEY);

			if (this.depositCounter != null && !this.depositCounterStep.equals(this.depositCounter.getCounterStep())) {
				this.depositCounterStep = this.depositCounter.getCounterStep();
			}
			
			if (this.depositLocalCount >= this.depositCounterStep) {
				this.depositCounter.setCurrentCounter(currentCounter + this.depositCounterStep);
				this.idCounterDao.save(this.depositCounter);
				this.depositLocalCount = 0;
			}
		}
		
		if (this.depositCounter != null) {
			String counterDate = DateUtils.dateToString(this.depositCounter.getCounterDate(), Constants.DATE_FORMAT_SECOND_TRUNCATE);
			depositId.append(counterDate);
			depositId.append(this.depositCounter.getCounterKey());
			depositId.append(this.depositCounter.getCurrentCounter());
			
			this.depositLocalCount++;
		}
		
		return depositId.toString();
	}
	
	/**
	 * Generate unique withdrawal id.
	 *
	 * @return the string
	 */
	public synchronized String generateUniqueWithdrawalId() {
		StringBuffer withdrawalId = new StringBuffer();
		if (this.withdrawalCounter == null || this.withdrawalLocalCount >= this.withdrawalCounterStep) {
			Integer currentCounter = 0;
			if (this.withdrawalCounter != null) {
				currentCounter = this.withdrawalCounter.getCurrentCounter();
			}
			
			this.withdrawalCounter = this.idCounterDao.getByCounterKey(Constants.IdCounterKey.WITHDRAW_ID_COUNTER_KEY);

			if (this.withdrawalCounter != null && !this.withdrawalCounterStep.equals(this.withdrawalCounter.getCounterStep())) {
				this.withdrawalCounterStep = this.withdrawalCounter.getCounterStep();
			}
			
			if (this.withdrawalLocalCount >= this.withdrawalCounterStep) {
				this.withdrawalCounter.setCurrentCounter(currentCounter + this.withdrawalCounterStep);
				this.idCounterDao.save(this.withdrawalCounter);
				this.withdrawalLocalCount = 0;
			}
		}
		
		if (this.withdrawalCounter != null) {
			String counterDate = DateUtils.dateToString(this.withdrawalCounter.getCounterDate(), Constants.DATE_FORMAT_SECOND_TRUNCATE);
			withdrawalId.append(counterDate);
			withdrawalId.append(this.withdrawalCounter.getCounterKey());
			withdrawalId.append(this.withdrawalCounter.getCurrentCounter());
			
			this.withdrawalLocalCount++;
		}
		
		return withdrawalId.toString();
	}
}
